package com.ht.shortlink.project.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ht.shortlink.project.dao.entity.LinkAccessLogsDO;
import com.ht.shortlink.project.dao.entity.LinkAccessStatsDO;
import com.ht.shortlink.project.dao.entity.LinkLocaleStatsDO;
import com.ht.shortlink.project.dao.mapper.*;
import com.ht.shortlink.project.dto.req.ShortLinkStatsAccessRecordsGroupReqDTO;
import com.ht.shortlink.project.dto.req.ShortLinkStatsAccessRecordsReqDTO;
import com.ht.shortlink.project.dto.req.ShortLinkStatsGroupReqDTO;
import com.ht.shortlink.project.dto.req.ShortLinkStatsReqDTO;
import com.ht.shortlink.project.dto.resp.*;
import com.ht.shortlink.project.service.IShortLinkStatsService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

@Service
@RequiredArgsConstructor
public class ShortLinkStatsServiceImpl implements IShortLinkStatsService {
    private final LinkAccessStatsMapper linkAccessStatsMapper;
    private final LinkAccessLogsMapper linkAccessLogsMapper;
    private final LinkLocaleStatsMapper linkLocaleStatsMapper;
    private final LinkBrowserStatsMapper linkBrowserStatsMapper;
    private final LinkOsStatsMapper linkOsStatsMapper;
    private final LinkNetworkStatsMapper linkNetworkStatsMapper;
    private final LinkDeviceStatsMapper linkDeviceStatsMapper;

    @Override
    public ShortLinkStatsRespDTO oneShortLinkStats(ShortLinkStatsReqDTO requestParam) {
        // 根据短链接查询基本访问数据
        LinkAccessStatsDO pvUvUipByShortLink = linkAccessLogsMapper.findPvUvUipByShortLink(requestParam);


        // 根据短链接查询每日基础监控数据
        List<LinkAccessStatsDO> dailyStatsList = linkAccessStatsMapper.listStatsByLink(requestParam);
        if(CollUtil.isEmpty(dailyStatsList)){
            return null;
        }
        // 处理给定日期范围内基础监控数据
        List<ShortLinkStatsAccessDailyRespDTO> dailyRespDTOList = new ArrayList<>();
        List<String> rangeDate = DateUtil.rangeToList(DateUtil.parse(requestParam.getStartDate()), DateUtil.parse(requestParam.getEndDate()), DateField.DAY_OF_MONTH)
                .stream()
                .map(DateUtil::formatDate)
                .toList();
        rangeDate.forEach(each -> dailyStatsList.stream()
                .filter(item -> ObjectUtil.equals(each, DateUtil.formatDate(item.getDate())))
                .findFirst()
                .ifPresentOrElse(item -> {
                    ShortLinkStatsAccessDailyRespDTO linkStatsAccessDailyRespDTO = ShortLinkStatsAccessDailyRespDTO.builder()
                            .pv(item.getPv())
                            .uv(item.getUv())
                            .uip(item.getUip())
                            .date(each)
                            .build();
                    dailyRespDTOList.add(linkStatsAccessDailyRespDTO);
                }, () -> {
                    ShortLinkStatsAccessDailyRespDTO linkStatsAccessDailyRespDTO = ShortLinkStatsAccessDailyRespDTO.builder()
                            .pv(0)
                            .uv(0)
                            .uip(0)
                            .date(each)
                            .build();
                    dailyRespDTOList.add(linkStatsAccessDailyRespDTO);
                })
        );
        // 根据短链接查询访问地区监控数据
        List<ShortLinkStatsLocaleRespDTO> localeRespDTOList = new ArrayList<>();
        List<LinkLocaleStatsDO> linkLocaleStatsDOList = linkLocaleStatsMapper.listLocaleStatsByLink(requestParam);
        int localeSum = linkLocaleStatsDOList.stream()
                .mapToInt(LinkLocaleStatsDO::getCnt)
                .sum();
        linkLocaleStatsDOList.forEach(each -> {
            double ratio = (double) each.getCnt() / localeSum;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsLocaleRespDTO localeRespDTO = ShortLinkStatsLocaleRespDTO.builder()
                    .cnt(each.getCnt())
                    .locale(each.getProvince())
                    .ratio(actualRatio)
                    .build();
            localeRespDTOList.add(localeRespDTO);
        });
        // 根据短链接查询每小时监控数据
        List<Integer> hourStatsRespDTOList = new ArrayList<>();
        List<LinkAccessStatsDO> listStatsHourList = linkAccessStatsMapper.listStatsHourByLink(requestParam);
        for (int i = 0; i < 24; i++) {
            AtomicInteger hour = new AtomicInteger(i);
            Integer hourCnt = listStatsHourList.stream()
                    .filter(item -> ObjectUtil.equals(hour.get(), item.getHour()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            hourStatsRespDTOList.add(hourCnt);
        }
        // 根据短链接查询高频ip监控数据
        List<ShortLinkStatsTopIPRespDTO> topIPRespList = new ArrayList<>();
        List<HashMap<String, Object>> topIPStatsList = linkAccessLogsMapper.findTopIPByShortLink(requestParam);
        topIPStatsList.forEach(each -> {
            ShortLinkStatsTopIPRespDTO shortLinkStatsTopIPRespDTO = ShortLinkStatsTopIPRespDTO.builder()
                    .ip(each.get("ip").toString())
                    .cnt(Integer.parseInt(each.get("count").toString()))
                    .build();
            topIPRespList.add(shortLinkStatsTopIPRespDTO);
        });
        // 根据短链接查询一周的每一天监控数据
        List<Integer> weekdayStatsRespDTOList = new ArrayList<>();
        List<LinkAccessStatsDO> listStatsWeekdayList = linkAccessStatsMapper.listStatsWeekdayByLink(requestParam);
        for (int i = 1; i <= 7; i++) {
            AtomicInteger weekday = new AtomicInteger(i);
            Integer weekdayCnt = listStatsWeekdayList.stream()
                    .filter(item -> ObjectUtil.equals(weekday.get(), item.getWeekday()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            weekdayStatsRespDTOList.add(weekdayCnt);
        }
        // 根据短链接查询浏览器监控数据
        List<ShortLinkStatsBrowserRespDTO> browserStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> browserByLink = linkBrowserStatsMapper.listStatsBrowserByLink(requestParam);
        int browserCnt = browserByLink.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        browserByLink.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / browserCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsBrowserRespDTO shortLinkStatsTopIPRespDTO = ShortLinkStatsBrowserRespDTO.builder()
                    .browser(each.get("browser").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            browserStatsRespList.add(shortLinkStatsTopIPRespDTO);
        });
        // 根据短链接查询操作系统监控数据
        List<ShortLinkStatsOsRespDTO> osStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> osByLink = linkOsStatsMapper.listStatsOsByLink(requestParam);
        int osCnt = osByLink.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        osByLink.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / osCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsOsRespDTO shortLinkStatsOsRespDTO = ShortLinkStatsOsRespDTO.builder()
                    .os(each.get("os").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            osStatsRespList.add(shortLinkStatsOsRespDTO);
        });
        // 根据短链接查询访问网络监控数据
        List<ShortLinkStatsNetworkRespDTO> networkStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> networkByLink = linkNetworkStatsMapper.listStatsNetworkByLink(requestParam);
        int networkCnt = networkByLink.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        networkByLink.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / networkCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsNetworkRespDTO shortLinkStatsNetworkRespDTO = ShortLinkStatsNetworkRespDTO.builder()
                    .network(each.get("network").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            networkStatsRespList.add(shortLinkStatsNetworkRespDTO);
        });
        // 根据短链接查询访问设备监控数据
        List<ShortLinkStatsDeviceRespDTO> deviceStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> deviceByLink = linkDeviceStatsMapper.listStatsDeviceByLink(requestParam);
        int deviceCnt = deviceByLink.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        deviceByLink.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / deviceCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsDeviceRespDTO shortLinkStatsDeviceRespDTO = ShortLinkStatsDeviceRespDTO.builder()
                    .device(each.get("device").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            deviceStatsRespList.add(shortLinkStatsDeviceRespDTO);
        });
        // 根据短链接查询访客类型监控数据
        List<ShortLinkStatsUvRespDTO> uvTypeStats = new ArrayList<>();
        HashMap<String, Object> findUvTypeByShortLink = linkAccessLogsMapper.findUvTypeCntByShortLink(requestParam);
        int oldUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByShortLink)
                .map(each -> each.get("oldUserCnt"))
                .map(Object::toString)
                .orElse("0"));
        int newUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeByShortLink)
                        .map(each -> each.get("newUserCnt"))
                        .map(Object::toString)
                        .orElse("0"));
        int uvSum = oldUserCnt + newUserCnt;
        double oldRatio = (double) oldUserCnt / uvSum;
        double actualOldRatio = Math.round(oldRatio * 100.0) / 100.0;
        double newRatio = (double) newUserCnt / uvSum;
        double actualNewRatio = Math.round(newRatio * 100.0) / 100.0;
        ShortLinkStatsUvRespDTO newUvRespDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("newUser")
                .cnt(newUserCnt)
                .ratio(actualNewRatio)
                .build();
        uvTypeStats.add(newUvRespDTO);
        ShortLinkStatsUvRespDTO oldUvRespDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("oldUser")
                .cnt(oldUserCnt)
                .ratio(actualOldRatio)
                .build();
        uvTypeStats.add(oldUvRespDTO);

        return ShortLinkStatsRespDTO.builder()
                .pv(Optional.ofNullable(pvUvUipByShortLink)
                        .map(each -> each.getPv())
                        .orElse(0))
                .uv(Optional.ofNullable(pvUvUipByShortLink)
                        .map(each -> each.getUv())
                        .orElse(0))
                .uip(Optional.ofNullable(pvUvUipByShortLink)
                        .map(each -> each.getUip())
                        .orElse(0))
                .daily(dailyRespDTOList)
                .localeCnStats(localeRespDTOList)
                .hourStats(hourStatsRespDTOList)
                .weekdayStats(weekdayStatsRespDTOList)
                .topIpStats(topIPRespList)
                .browserStats(browserStatsRespList)
                .osStats(osStatsRespList)
                .uvTypeStats(uvTypeStats)
                .deviceStats(deviceStatsRespList)
                .networkStats(networkStatsRespList)
                .build();
    }

    @Override
    public ShortLinkStatsRespDTO groupShortLinkStats(ShortLinkStatsGroupReqDTO requestParam) {
        // 根据短链接查询基本访问数据
        LinkAccessStatsDO pvUvUipByGroup = linkAccessLogsMapper.findPvUvUipByGroup(requestParam);


        // 根据短链接查询每日基础监控数据
        List<LinkAccessStatsDO> dailyStatsList = linkAccessStatsMapper.listStatsByGroup(requestParam);
        if(CollUtil.isEmpty(dailyStatsList)){
            return null;
        }
        // 处理给定日期范围内基础监控数据
        List<ShortLinkStatsAccessDailyRespDTO> dailyRespDTOList = new ArrayList<>();
        List<String> rangeDate = DateUtil.rangeToList(DateUtil.parse(requestParam.getStartDate()), DateUtil.parse(requestParam.getEndDate()), DateField.DAY_OF_MONTH)
                .stream()
                .map(DateUtil::formatDate)
                .toList();
        rangeDate.forEach(each -> dailyStatsList.stream()
                .filter(item -> ObjectUtil.equals(each, DateUtil.formatDate(item.getDate())))
                .findFirst()
                .ifPresentOrElse(item -> {
                    ShortLinkStatsAccessDailyRespDTO linkStatsAccessDailyRespDTO = ShortLinkStatsAccessDailyRespDTO.builder()
                            .pv(item.getPv())
                            .uv(item.getUv())
                            .uip(item.getUip())
                            .date(each)
                            .build();
                    dailyRespDTOList.add(linkStatsAccessDailyRespDTO);
                }, () -> {
                    ShortLinkStatsAccessDailyRespDTO linkStatsAccessDailyRespDTO = ShortLinkStatsAccessDailyRespDTO.builder()
                            .pv(0)
                            .uv(0)
                            .uip(0)
                            .date(each)
                            .build();
                    dailyRespDTOList.add(linkStatsAccessDailyRespDTO);
                })
        );
        // 根据短链接查询访问地区监控数据
        List<ShortLinkStatsLocaleRespDTO> localeRespDTOList = new ArrayList<>();
        List<LinkLocaleStatsDO> linkLocaleStatsDOList = linkLocaleStatsMapper.listLocaleStatsByGroup(requestParam);
        int localeSum = linkLocaleStatsDOList.stream()
                .mapToInt(LinkLocaleStatsDO::getCnt)
                .sum();
        linkLocaleStatsDOList.forEach(each -> {
            double ratio = (double) each.getCnt() / localeSum;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsLocaleRespDTO localeRespDTO = ShortLinkStatsLocaleRespDTO.builder()
                    .cnt(each.getCnt())
                    .locale(each.getProvince())
                    .ratio(actualRatio)
                    .build();
            localeRespDTOList.add(localeRespDTO);
        });
        // 根据短链接查询每小时监控数据
        List<Integer> hourStatsRespDTOList = new ArrayList<>();
        List<LinkAccessStatsDO> listStatsHourList = linkAccessStatsMapper.listStatsHourByGroup(requestParam);
        for (int i = 0; i < 24; i++) {
            AtomicInteger hour = new AtomicInteger(i);
            Integer hourCnt = listStatsHourList.stream()
                    .filter(item -> ObjectUtil.equals(hour.get(), item.getHour()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            hourStatsRespDTOList.add(hourCnt);
        }
        // 根据短链接查询高频ip监控数据
        List<ShortLinkStatsTopIPRespDTO> topIPRespList = new ArrayList<>();
        List<HashMap<String, Object>> topIPStatsList = linkAccessLogsMapper.findTopIPByGroup(requestParam);
        topIPStatsList.forEach(each -> {
            ShortLinkStatsTopIPRespDTO shortLinkStatsTopIPRespDTO = ShortLinkStatsTopIPRespDTO.builder()
                    .ip(each.get("ip").toString())
                    .cnt(Integer.parseInt(each.get("count").toString()))
                    .build();
            topIPRespList.add(shortLinkStatsTopIPRespDTO);
        });
        // 根据短链接查询一周的每一天监控数据
        List<Integer> weekdayStatsRespDTOList = new ArrayList<>();
        List<LinkAccessStatsDO> listStatsWeekdayList = linkAccessStatsMapper.listStatsWeekdayByGroup(requestParam);
        for (int i = 1; i <= 7; i++) {
            AtomicInteger weekday = new AtomicInteger(i);
            Integer weekdayCnt = listStatsWeekdayList.stream()
                    .filter(item -> ObjectUtil.equals(weekday.get(), item.getWeekday()))
                    .findFirst()
                    .map(LinkAccessStatsDO::getPv)
                    .orElse(0);
            weekdayStatsRespDTOList.add(weekdayCnt);
        }
        // 根据短链接查询浏览器监控数据
        List<ShortLinkStatsBrowserRespDTO> browserStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> browserByGroup = linkBrowserStatsMapper.listStatsBrowserByGroup(requestParam);
        int browserCnt = browserByGroup.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        browserByGroup.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / browserCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsBrowserRespDTO shortLinkStatsTopIPRespDTO = ShortLinkStatsBrowserRespDTO.builder()
                    .browser(each.get("browser").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            browserStatsRespList.add(shortLinkStatsTopIPRespDTO);
        });
        // 根据短链接查询操作系统监控数据
        List<ShortLinkStatsOsRespDTO> osStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> osByGroup = linkOsStatsMapper.listStatsOsByGroup(requestParam);
        int osCnt = osByGroup.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        osByGroup.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / osCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsOsRespDTO shortLinkStatsOsRespDTO = ShortLinkStatsOsRespDTO.builder()
                    .os(each.get("os").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            osStatsRespList.add(shortLinkStatsOsRespDTO);
        });
        // 根据短链接查询访问网络监控数据
        List<ShortLinkStatsNetworkRespDTO> networkStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> networkByGroup = linkNetworkStatsMapper.listStatsNetworkByGroup(requestParam);
        int networkCnt = networkByGroup.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        networkByGroup.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / networkCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsNetworkRespDTO shortLinkStatsNetworkRespDTO = ShortLinkStatsNetworkRespDTO.builder()
                    .network(each.get("network").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            networkStatsRespList.add(shortLinkStatsNetworkRespDTO);
        });
        // 根据短链接查询访问设备监控数据
        List<ShortLinkStatsDeviceRespDTO> deviceStatsRespList = new ArrayList<>();
        List<HashMap<String, Object>> deviceByGroup = linkDeviceStatsMapper.listStatsDeviceByGroup(requestParam);
        int deviceCnt = deviceByGroup.stream()
                .mapToInt(each -> Integer.parseInt(each.get("cnt").toString()))
                .sum();
        deviceByGroup.forEach(each -> {
            double ratio = (double) Integer.parseInt(each.get("cnt").toString()) / deviceCnt;
            double actualRatio = Math.round(ratio * 100.0) / 100.0;
            ShortLinkStatsDeviceRespDTO shortLinkStatsDeviceRespDTO = ShortLinkStatsDeviceRespDTO.builder()
                    .device(each.get("device").toString())
                    .cnt(Integer.parseInt(each.get("cnt").toString()))
                    .ratio(actualRatio)
                    .build();
            deviceStatsRespList.add(shortLinkStatsDeviceRespDTO);
        });
        // 根据短链接查询访客类型监控数据
        List<ShortLinkStatsUvRespDTO> uvTypeStats = new ArrayList<>();
        HashMap<String, Object> findUvTypeCntByGroup = linkAccessLogsMapper.findUvTypeCntByGroup(requestParam);
        int oldUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeCntByGroup)
                        .map(each -> each.get("oldUserCnt"))
                        .map(Object::toString)
                        .orElse("0"));
        int newUserCnt = Integer.parseInt(
                Optional.ofNullable(findUvTypeCntByGroup)
                        .map(each -> each.get("newUserCnt"))
                        .map(Object::toString)
                        .orElse("0"));
        int uvSum = oldUserCnt + newUserCnt;
        double oldRatio = (double) oldUserCnt / uvSum;
        double actualOldRatio = Math.round(oldRatio * 100.0) / 100.0;
        double newRatio = (double) newUserCnt / uvSum;
        double actualNewRatio = Math.round(newRatio * 100.0) / 100.0;
        ShortLinkStatsUvRespDTO newUvRespDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("newUser")
                .cnt(newUserCnt)
                .ratio(actualNewRatio)
                .build();
        uvTypeStats.add(newUvRespDTO);
        ShortLinkStatsUvRespDTO oldUvRespDTO = ShortLinkStatsUvRespDTO.builder()
                .uvType("oldUser")
                .cnt(oldUserCnt)
                .ratio(actualOldRatio)
                .build();
        uvTypeStats.add(oldUvRespDTO);

        return ShortLinkStatsRespDTO.builder()
                .pv(Optional.ofNullable(pvUvUipByGroup)
                        .map(each -> each.getPv())
                        .orElse(0))
                .uv(Optional.ofNullable(pvUvUipByGroup)
                        .map(each -> each.getUv())
                        .orElse(0))
                .uip(Optional.ofNullable(pvUvUipByGroup)
                        .map(each -> each.getUip())
                        .orElse(0))
                .daily(dailyRespDTOList)
                .localeCnStats(localeRespDTOList)
                .hourStats(hourStatsRespDTOList)
                .weekdayStats(weekdayStatsRespDTOList)
                .topIpStats(topIPRespList)
                .browserStats(browserStatsRespList)
                .osStats(osStatsRespList)
                .uvTypeStats(uvTypeStats)
                .deviceStats(deviceStatsRespList)
                .networkStats(networkStatsRespList)
                .build();
    }

    @Override
    public IPage<ShortLinkStatsAccessRecordsRespDTO> queryLinkStatsAccessRecords(ShortLinkStatsAccessRecordsReqDTO requestParam){
        LambdaQueryWrapper<LinkAccessLogsDO> queryWrapper = Wrappers.lambdaQuery(LinkAccessLogsDO.class)
                .eq(LinkAccessLogsDO::getFullShortUrl, requestParam.getFullShortUrl())
                .eq(LinkAccessLogsDO::getGid, requestParam.getGid())
                .between(LinkAccessLogsDO::getCreateTime, requestParam.getStartDate(), requestParam.getEndDate())
                .eq(LinkAccessLogsDO::getDelFlag, 0);
        IPage<LinkAccessLogsDO> linkAccessLogsDOIPage = linkAccessLogsMapper.selectPage(requestParam, queryWrapper);
        // 空值检查
        if (linkAccessLogsDOIPage == null || CollUtil.isEmpty(linkAccessLogsDOIPage.getRecords())) {
            return new Page<>();
        }
        // 得到初始最终结果
        IPage<ShortLinkStatsAccessRecordsRespDTO> actualResult = linkAccessLogsDOIPage.convert(each -> BeanUtil.toBean(each, ShortLinkStatsAccessRecordsRespDTO.class));
        // 设置访客类型
        List<String> userList = actualResult.getRecords().stream()
                .map(ShortLinkStatsAccessRecordsRespDTO::getUser)
                .toList();
        List<HashMap<String, Object>> uvTypeList = linkAccessLogsMapper.queryUvType(requestParam.getFullShortUrl(), requestParam.getGid(), requestParam.getStartDate(), requestParam.getEndDate(), userList);
        actualResult.getRecords().forEach(each -> {
            String uvType = uvTypeList.stream()
                    .filter(item -> ObjectUtil.equals(each.getUser(), item.get("user").toString()))
                    .findFirst()
                    .map(item -> item.get("uvType"))
                    .map(Object::toString)
                    .orElse("老访客");
            each.setUvType(uvType);
        });

        return actualResult;
    }

    @Override
    public IPage<ShortLinkStatsAccessRecordsGroupRespDTO> queryGroupStatsAccessRecords(ShortLinkStatsAccessRecordsGroupReqDTO requestParam) {
        LambdaQueryWrapper<LinkAccessLogsDO> queryWrapper = Wrappers.lambdaQuery(LinkAccessLogsDO.class)
                .eq(LinkAccessLogsDO::getGid, requestParam.getGid())
                .between(LinkAccessLogsDO::getCreateTime, requestParam.getStartDate(), requestParam.getEndDate())
                .eq(LinkAccessLogsDO::getDelFlag, 0);
        IPage<LinkAccessLogsDO> linkAccessLogsDOIPage = linkAccessLogsMapper.selectPage(requestParam, queryWrapper);
        // 空值检查
        if (linkAccessLogsDOIPage == null || CollUtil.isEmpty(linkAccessLogsDOIPage.getRecords())) {
            return new Page<>();
        }
        // 得到初始最终结果
        IPage<ShortLinkStatsAccessRecordsGroupRespDTO> actualResult = linkAccessLogsDOIPage.convert(each -> BeanUtil.toBean(each, ShortLinkStatsAccessRecordsGroupRespDTO.class));
        // 设置访客类型
        List<String> userList = actualResult.getRecords().stream()
                .map(ShortLinkStatsAccessRecordsGroupRespDTO::getUser)
                .toList();
        List<HashMap<String, Object>> uvTypeList = linkAccessLogsMapper.queryGroupUvType(requestParam.getGid(), requestParam.getStartDate(), requestParam.getEndDate(), userList);
        actualResult.getRecords().forEach(each -> {
            String uvType = uvTypeList.stream()
                    .filter(item -> ObjectUtil.equals(each.getUser(), item.get("user").toString()))
                    .findFirst()
                    .map(item -> item.get("uvType"))
                    .map(Object::toString)
                    .orElse("老访客");
            each.setUvType(uvType);
        });

        return actualResult;
    }


}
